package com.orgcent.tuangou.xml;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

/**
 * 使用SAX方式解析RSS中的xml
 */
public class ModelHandler<T> extends AbstractHandler {
	/**
	 * 记录最近的标签
	 */
	private final Stack<String> tagStack = new Stack<String>();
	private List<T> mResult = new ArrayList<T>();
	private Class<T> mClass;

	private Field[] mFields;

	private StringBuilder builder = new StringBuilder();

	public List<T> getList(String uri, HashMap<String, Object> args) {
		int i = processRequest(uri, args); // 处理请求
		if (-1 == i) { // 加载失败
			return null;
		}
		return mResult;
	}

	private int processRequest(String uri, HashMap<String, Object> args) {
		HttpClient client = new DefaultHttpClient();
		HttpResponse resp = null;
		// 设置参数
		HttpParams params = client.getParams();
		StringBuilder urlBuilder = new StringBuilder(uri);
		if (null != args) {
			int size = args.size();
			if (size > 0) {
				urlBuilder.append("?");
			}
			for (Map.Entry<String, Object> entry : args.entrySet()) {
				urlBuilder.append(entry.getKey()).append("=").append(
						entry.getValue()).append("&");
			}
		}
		// 超时时间
		HttpConnectionParams.setConnectionTimeout(params, 20000);
		HttpConnectionParams.setSoTimeout(params, 35000);

		try {
			resp = client.execute(new HttpGet(urlBuilder.toString()));
			BufferedHttpEntity entity = new BufferedHttpEntity(resp.getEntity());
			InputStream is = entity.getContent();
			if (!parse(is)) {// 解析xml
				return -1;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return -1; // 加载失败
		} finally {
			client.getConnectionManager().shutdown();
		}
		return 0;
	}

	@Override
	public void characters(char[] ch, int start, int length)// 获取所有文本
			throws SAXException {
		// String chars = new String(ch, start, length).trim();
		// if (!"".equals(chars)) {
		// setText(chars);
		// }
		builder.append(ch, start, length);
	}

	private void setText(String text) {
		String tagName = (String) tagStack.peek();// 查看栈顶对象而不移除它

		T tempObj = null;
		int size = mResult.size();
		if (size > 0) {
			tempObj = mResult.get(size - 1);
		}
		try {
			if (null != tempObj) {// 根据当前标签名称给对应的对象中的属性赋值[标签名==对象属性名]
				Field f = null;
				Field[] tempFields = mFields;
				for (Field field : tempFields) {
					if (field.getName().equalsIgnoreCase(tagName)) {
						f = field;
						break;
					}
				}
				if (null != f) {
					f.setAccessible(true);
					f.set(tempObj, text);
					f = null;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public ModelHandler(Class<T> mClass) {
		this.mClass = mClass;
		// 获取属性
		mFields = mClass.getDeclaredFields();
	}

	@Override
	public void endDocument() throws SAXException {
		mFields = null;
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		setText(builder.toString().trim());
		builder.setLength(0);
		tagStack.pop();// 移除栈顶对象并作为此函数的值返回该对象
	}

	@Override
	public boolean parse(String xmlString) {
		try {
			super.parserXml(this, xmlString);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public boolean parse(InputStream is) {
		try {
			super.parserXml(is, this);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public void startDocument() throws SAXException {
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		Class<T> tempClass = mClass;
		if (tempClass.getSimpleName().equalsIgnoreCase(localName)) {
			try {
				mResult.add(tempClass.newInstance());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		tagStack.push(localName);
	}
}
